#pragma once

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <queue>

#define NUM 8

template<class T>
class BlockQueue{
  private:
    std::queue<T> q;
    int capacity;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
  private:
    bool IsFull()
    {
      return q.size() == capacity;
    }
    bool IsEmpty()
    {
      return q.size() == 0;
    }
  public:
    BlockQueue(int _capacity = NUM):capacity(_capacity)
    {
      pthread_mutex_init(&lock, nullptr);
      pthread_cond_init(&full, nullptr);
      pthread_cond_init(&empty, nullptr);
    }
    void Push(const T& data)
    {
      //如果队列已满
      pthread_mutex_lock(&lock);
      //避免伪唤醒或者函数调用失败
      while(IsFull()){
        pthread_cond_wait(&full, &lock);
      }//队列未满
      
      q.push(data); 
      if(q.size() >= capacity / 2){
        pthread_cond_signal(&empty);
      }
      pthread_mutex_unlock(&lock);
      usleep(10);
    }
    void Pop(T& data)
    {
      pthread_mutex_lock(&lock);
      //避免伪唤醒或者函数调用失败
      while(IsEmpty()){
        pthread_cond_wait(&empty, &lock);
      }

      data = q.front();
      q.pop();
      if(q.size() <= capacity / 2){
        pthread_cond_signal(&full);
      }
      pthread_mutex_unlock(&lock);
      usleep(10);
    }
    ~BlockQueue()
    {
      //销毁锁和条件变量
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full); 
      pthread_cond_destroy(&empty); 
    }
};
